package com.icloud.common.web.config;

import cn.hutool.core.date.DateUtil;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;

@Slf4j
@Configuration
public class JacksonConfig {

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer customizer() {
        return jacksonObjectMapperBuilder -> {
            //BigDecimal
            jacksonObjectMapperBuilder.serializerByType(BigDecimal.class, new JsonSerializer<BigDecimal>() {
                @Override
                public void serialize(BigDecimal bigDecimal, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
                    jsonGenerator.writeString(bigDecimal.toPlainString());
                }
            });
            //Date
            jacksonObjectMapperBuilder.serializerByType(Date.class, new JsonSerializer<Date>() {
                @Override
                public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
                    jsonGenerator.writeNumber(date.toInstant().getEpochSecond());
                }
            });
            //LocalDateTime
            jacksonObjectMapperBuilder.serializerByType(LocalDateTime.class, new JsonSerializer<LocalDateTime>() {
                @Override
                public void serialize(LocalDateTime date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
                    jsonGenerator.writeNumber(date.atZone(ZoneId.systemDefault()).toEpochSecond());
                }
            });
            //LocalTime
            jacksonObjectMapperBuilder.serializerByType(LocalTime.class, new JsonSerializer<LocalTime>() {
                @Override
                public void serialize(LocalTime time, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
                    jsonGenerator.writeString(time.toString());
                }
            });

            jacksonObjectMapperBuilder.deserializerByType(LocalDateTime.class, new JsonDeserializer<LocalDateTime>(){
                @Override
                public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
                    long timestamp = jsonParser.getValueAsLong();
                    if(timestamp == 0) {
                        String source = jsonParser.getValueAsString();
                        if(source.trim().length() == 0) {
                            return null;
                        }
                        Date date = DateUtil.parse(source);
                        timestamp = date.toInstant().getEpochSecond();
                    }
                    return LocalDateTime.ofInstant(Instant.ofEpochSecond(timestamp), ZoneId.systemDefault());
                }
            });

            jacksonObjectMapperBuilder.deserializerByType(Date.class, new JsonDeserializer<Date>(){
                @Override
                public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
                    long timestamp = jsonParser.getValueAsLong();
                    if(timestamp == 0) {
                        String source = jsonParser.getValueAsString();
                        if(source.trim().length() == 0) {
                            return null;
                        }else {
                            return DateUtil.parse(source);
                        }
                    }else {
                        return Date.from(Instant.ofEpochSecond(timestamp));
                    }
                }
            });
        };
    }

    /**
     * 将前端传递的时间字符串转换为LocalDateTime
     */
    @Bean
    public Converter<String, LocalDateTime> localDateTimeConverter() {
        return new Converter<String, LocalDateTime>() {
            @Override
            public LocalDateTime convert(String source) {
                if(source.trim().length() == 0) {
                    return null;
                }
                try {
                    return LocalDateTime.parse(source);
                }catch (Exception e) {
                    return LocalDateTime.parse(source, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                }
            }
        };
    }

    /**
     * 将前端传递的事件字符串转换为Date
     */
    @Bean
    public Converter<String, Date> dateConverter() {
        return new Converter<String, Date>() {
            @Override
            public Date convert(String source) {
                if(source.trim().length() == 0) {
                    return null;
                }
                return DateUtil.parse(source);
            }
        };
    }
}
